In the V1.1.0 hardware design, the Ethernet PHY chip was replaced from RTL8211E to RTL8211F.
The TXDLY setting for RTL8211F requires configuration through the internal registers of the PHY, rather than being able to be adjusted using hardware resistors like in the case of RTL8211E.
In the xlnx-linux PHY driver, for the PHY_INTERFACE_MODE_GMII interface mode, the TXDLY function is disabled by default.
Currently, the PHY interface mode used by the PL-side expansion port is PHY_interface_MODE_GMII. As a result, under the default driver configuration, the TXDLY function of RTL8211F is not enabled. This may lead to inconsistent TX timing between the PHY and the MAC layer, thereby affecting the normal operation of the port.
The driver is located in linux-xlnx/drivers/net/phy/realtek.c. Please modify the rtl8211f_config_init function accordingly.
static int rtl8211f_config_init(struct phy_device *phydev){ ...
switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: val_txdly = 0; val_rxdly = 0; break;
case PHY_INTERFACE_MODE_RGMII_RXID: val_txdly = 0; val_rxdly = RTL8211F_RX_DELAY; break;
case PHY_INTERFACE_MODE_RGMII_TXID: val_txdly = RTL8211F_TX_DELAY; val_rxdly = 0; break;
case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_GMII: /* Added code for PL side PHY */ val_txdly = RTL8211F_TX_DELAY; val_rxdly = RTL8211F_RX_DELAY; break;
default: return 0; }
.....}After the modification, it is necessary to recompile the image using Petalinux.
Right-click on src to create a new folder:
Create the relevant .c and .h files as shown below:
Add the required header files:
The development board acts as a TCP server (port 12345) and echoes received data back to the sender.
x//TCP server code writing process: socket() → bind() → listen() → accept() → recv()/send() → close()// start the serverint start_server(void) { struct sockaddr_in addr;
server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket"); return -1; }
memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(SERVER_PORT); addr.sin_addr.s_addr = INADDR_ANY;
if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); close(server_fd); server_fd = -1; return -1; }
if (listen(server_fd, 5) < 0) { perror("listen"); close(server_fd); server_fd = -1; return -1; }
printf("Server started on port %d...\n", SERVER_PORT); return server_fd;}
// handle client sessionvoid handle_client(int client_sock) { ssize_t len;
while ((len = read(client_sock, rcv_buf, sizeof(rcv_buf) - 1)) > 0) { rcv_buf[len] = '\0'; printf("Received: %s\n", rcv_buf); write(client_sock, rcv_buf, len); // echo back }
printf("Client disconnected.\n"); close(client_sock);}
// server thread functionvoid* server_thread_func(void* arg) { while (1) { if (start_server() < 0) { sleep(2); // avoid busy loop if server fails to start continue; }
while (1) { int client_sock = accept(server_fd, NULL, NULL); if (client_sock < 0) { close(server_fd); server_fd = -1; break; }
handle_client(client_sock); } }}
Using the network debugging assistant NetAssist as a client to connect with the implemented server for data transmission and reception.
Right-click on src to create a new folder:
Create the relevant .c and .h files as shown below:
Add the required header files:
The development board acts as a TCP client. After connecting to a server (which can be started on a computer), it will echo back data received from the server.
xxxxxxxxxx//TCP client code writing process:socket() → connect() → send()/recv() → close()
// set host(server) IP and portvoid set_host_ip_port(int ip[4], uint16_t port) { if (!ip || port == 0) { return; }
pthread_mutex_lock(&host_mutex); memcpy(host_ip, ip, sizeof(host_ip)); host_port = port; pthread_mutex_unlock(&host_mutex);}
// Connect to serverint connect_to_server(const char *ip, int port) { int sockfd; struct sockaddr_in serv_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { return -1; }
memset(&serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &serv_addr.sin_addr) <= 0) { close(sockfd); return -1; }
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) { close(sockfd); return -1; }
printf("Connected to server %s:%d\n", ip, port); return sockfd;}
// receive data from server and send backint recv_handler(int sockfd) { static char buffer[BUFFER_SIZE]; ssize_t sent_len, recv_len;
recv_len = recv(sockfd, buffer, sizeof(buffer) - 1, 0); if (recv_len <= 0) { return -1; } buffer[recv_len] = '\0'; printf("Server replied: %s\n", buffer);
sent_len = send(sockfd, buffer, strlen(buffer), 0); if (sent_len < 0) { return -1; }
return 0;}
// Client thread functionvoid *client_pthread_func(void *arg){ int port; char ip_str[16];
while (1) { if (!check_host_ip_valid()) { sleep(1); continue; }
get_host_ip_str(ip_str, sizeof(ip_str)); pthread_mutex_lock(&host_mutex); port = host_port; pthread_mutex_unlock(&host_mutex);
int sockfd = connect_to_server(ip_str, port); if (sockfd < 0) { sleep(1); continue; }
while (1) { if (recv_handler(sockfd) < 0) { close(sockfd); sockfd = -1; break; // Disconnected due to error, try to connect again } sleep(1); } } return NULL;}First, start the server on the computer, then launch the program in Vitis.
After configuring the host IP and port, it will connect to the server. When the server sends data to the client on the development board, the development board will send the received data back to the server.